using System.Collections.Generic;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEngine;

namespace GridSystem.Editor
{
    [EditorTool("PlaceableObject Cell Painter", typeof(PlaceableObject))]
    public class PlaceableObjectCellPainter : EditorTool
    {
        private enum BrushMode { [InspectorName("画笔")] Paint, [InspectorName("橡皮擦")] Erase }
        private enum BrushShape { [InspectorName("矩形")] Square, [InspectorName("圆形")] Circle }

        private BrushMode _brushMode = BrushMode.Paint;
        private BrushShape _brushShape = BrushShape.Square;
        private int _brushSize = 1;
        private Rect _windowRect = new(5, 0, 200, 110);
        private bool _isInitialPositionSet = false;

        private static GUIContent _toolbarIcon;
        private static GUIContent ToolbarIcon
        {
            get
            {
                if (_toolbarIcon == null)
                {
                    _toolbarIcon = EditorGUIUtility.isProSkin ? EditorGUIUtility.IconContent("d_Grid.PaintTool") : EditorGUIUtility.IconContent("Grid.PaintTool");
                    _toolbarIcon.tooltip = "单元格绘制工具";
                }
                return _toolbarIcon;
            }
        }

        public override GUIContent toolbarIcon => ToolbarIcon;

        public override void OnToolGUI(EditorWindow window)
        {
            if (window is not SceneView sceneView) return;

            PlaceableObject placeable = target as PlaceableObject;
            if (placeable == null) return;

            HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
            Event e = Event.current;

            if (!_isInitialPositionSet || e.type == EventType.Layout)
            {
                _windowRect.y = sceneView.position.height - _windowRect.height - 30;
                _isInitialPositionSet = true;
            }
            Vector3 planePoint = placeable.transform.TransformPoint(new Vector3(0, placeable.yOffset, 0));
            Plane plane = new Plane(placeable.transform.up, planePoint);
            Ray ray = HandleUtility.GUIPointToWorldRay(e.mousePosition);

            if (plane.Raycast(ray, out float enter))
            {
                Vector3 worldHitPoint = ray.GetPoint(enter);
                Vector2Int localGridPos = placeable.WorldToLocal(worldHitPoint);

                BrushMode currentMode = e.alt ? BrushMode.Erase : _brushMode;

                List<Vector2Int> cellsInBrush = GetCellsInBrush(localGridPos);
                DrawBrushPreview(placeable, cellsInBrush, currentMode);

                if (e.type == EventType.MouseDown || e.type == EventType.MouseDrag)
                {
                    if (e.button == 0 && !_windowRect.Contains(e.mousePosition))
                    {
                        ModifyCells(placeable, cellsInBrush, currentMode);
                        e.Use();
                    }
                }
            }

            Handles.BeginGUI();
            _windowRect = GUILayout.Window(GetHashCode(), _windowRect, DrawToolWindow, "单元格绘制工具");
            _windowRect.x = Mathf.Clamp(_windowRect.x, 5, sceneView.position.width - _windowRect.width - 5);
            _windowRect.y = Mathf.Clamp(_windowRect.y, 0, sceneView.position.height - _windowRect.height - 30);
            Handles.EndGUI();

            sceneView.Repaint();
        }

        private void DrawToolWindow(int id)
        {
            _brushMode = (BrushMode)EditorGUILayout.EnumPopup("笔刷模式", _brushMode);
            EditorGUILayout.LabelField("按住 [Alt] 临时使用橡皮擦");
            _brushShape = (BrushShape)EditorGUILayout.EnumPopup("笔刷形状", _brushShape);
            _brushSize = EditorGUILayout.IntSlider("笔刷大小", _brushSize, 1, 10);
            GUI.DragWindow();
        }

        private List<Vector2Int> GetCellsInBrush(Vector2Int center)
        {
            List<Vector2Int> cells = new List<Vector2Int>();
            int extent = _brushSize - 1;

            for (int x = -extent; x <= extent; x++)
            {
                for (int y = -extent; y <= extent; y++)
                {
                    if (_brushShape == BrushShape.Circle && new Vector2(x, y).magnitude > extent) continue;
                    cells.Add(center + new Vector2Int(x, y));
                }
            }
            return cells;
        }

        private void DrawBrushPreview(PlaceableObject placeable, List<Vector2Int> cells, BrushMode mode)
        {
            Color previewColor = mode == BrushMode.Paint ? Color.cyan : Color.red;
            previewColor.a = 0.5f;
            Matrix4x4 matrix = placeable.transform.localToWorldMatrix * Matrix4x4.Translate(new Vector3(0, placeable.yOffset, 0));
            using (new Handles.DrawingScope(matrix))
            {
                Vector3[] verts = new Vector3[4];
                float cellSize = placeable.cellSize;
                float halfSize = cellSize * 0.5f;

                foreach (Vector2Int cell in cells)
                {
                    Vector3 cellCenter = new Vector3(cell.x, 0, cell.y) * cellSize;
                    verts[0] = cellCenter + new Vector3(-halfSize, 0, -halfSize);
                    verts[1] = cellCenter + new Vector3(halfSize, 0, -halfSize);
                    verts[2] = cellCenter + new Vector3(halfSize, 0, halfSize);
                    verts[3] = cellCenter + new Vector3(-halfSize, 0, halfSize);
                    Handles.DrawSolidRectangleWithOutline(verts, previewColor, Color.clear);
                }
            }
        }

        private void ModifyCells(PlaceableObject placeable, List<Vector2Int> cells, BrushMode mode)
        {
            Undo.RecordObject(placeable, "修改PlaceableObject单元格");
            bool changed = false;
            foreach (Vector2Int cell in cells)
            {
                if (mode == BrushMode.Paint)
                {
                    if (!placeable.definedCells.Contains(cell))
                    {
                        placeable.definedCells.Add(cell);
                        changed = true;
                    }
                }
                else
                {
                    if (placeable.definedCells.Remove(cell))
                    {
                        changed = true;
                    }
                }
            }

            if (changed) EditorUtility.SetDirty(placeable);
        }
    }
}